import dayjs from 'dayjs'
import AES from 'crypto-js/aes'
import encUTF8 from 'crypto-js/enc-utf8'

/**
 * @desc  格式化时间
 * @param {(Object|string|number)} time
 * @param {string} format
 * @returns {string | null}
 */
export function formatDateTime(time = undefined, format = 'YYYY-MM-DD HH:mm:ss') {
  return dayjs(time).format(format)
}

export function formatDateTimeNoSecond(time = undefined, format = 'YYYY-MM-DD HH:mm') {
  return dayjs(time).format(format)
}

export function formatDate(date = undefined, format = 'YYYY-MM-DD') {
  return formatDateTime(date, format)
}

/**
 * @desc  函数节流
 * @param {Function} fn
 * @param {Number} wait
 * @returns {Function}
 */
export function throttle(fn, wait) {
  var context, args
  var previous = 0

  return function () {
    var now = +new Date()
    context = this
    args = arguments
    if (now - previous > wait) {
      fn.apply(context, args)
      previous = now
    }
  }
}

/**
 * @desc  函数防抖
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(method, wait, immediate) {
  let timeout
  return function (...args) {
    let context = this
    if (timeout) {
      clearTimeout(timeout)
    }
    // 立即执行需要两个条件，一是immediate为true，二是timeout未被赋值或被置为null
    if (immediate) {
      /**
       * 如果定时器不存在，则立即执行，并设置一个定时器，wait毫秒后将定时器置为null
       * 这样确保立即执行后wait毫秒内不会被再次触发
       */
      let callNow = !timeout
      timeout = setTimeout(() => {
        timeout = null
      }, wait)
      if (callNow) {
        method.apply(context, args)
      }
    } else {
      // 如果immediate为false，则函数wait毫秒后执行
      timeout = setTimeout(() => {
        /**
         * args是一个类数组对象，所以使用fn.apply
         * 也可写作method.call(context, ...args)
         */
        method.apply(context, args)
      }, wait)
    }
  }
}

/**
 *
 * @param {HTMLElement} el
 * @param {Function} cb
 * @return {ResizeObserver}
 */
export function useResize(el, cb) {
  const observer = new ResizeObserver((entries) => {
    cb(entries[0].contentRect)
  })
  observer.observe(el)
  return observer
}

export function once(fn) {
  if (typeof fn !== 'function') {
    throw new TypeError('once 期望传入一个函数')
  }
  return function () {
    if (fn) {
      const result = fn.apply(this, arguments)
      fn = null
      return result
    }
  }
}

export function generateRandomString(n) {
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < n; i++) {
    const randomIndex = Math.floor(Math.random() * characters.length)
    result += characters.charAt(randomIndex)
  }

  return result
}

const secret_value = 'OJDHUASEBUGXRBCD' //密匙 16位
const iv_value = 'OJ_DHU_NEW_AES_H' // 初始向量 initial vector 16位

// 密匙和向量处理
const secret = encUTF8.parse(secret_value)
const iv = encUTF8.parse(iv_value)

// 加密
export function encryptASE(value) {
  const encrypted = AES.encrypt(value, secret, {
    iv: iv,
    // mode 支持 CBC, CFB,CTB,ECB,OFB,OFB, 默认CBC
    // mode: CryptoJS.mode.CBC,

    // // NoPadding, zeropadding 默认Pkcs7 即 pkcs5
    // padding: CryptoJS.pad.Pkcs7
  })

  // 将加密结果转换为字符串，传输该段字符串(加密后的内容)
  return encrypted.toString()
}

// 解密
export function decryptASE(encrypted) {
  let decrypted = AES.decrypt(encrypted, secret, {
    iv: iv,
    // mode 支持 CBC, CFB,CTB,ECB,OFB,OFB, 默认CBC
    // mode: CryptoJS.mode.CBC,

    // // NoPadding, zeropadding 默认Pkcs7 即 pkcs5
    // padding: CryptoJS.pad.Pkcs7
  })

  // 将解密结果转换为utf8字符串
  return encUTF8.stringify(decrypted)
}
